#!/usr/bin/python
# -*- coding: UTF-8 -*-

"""
@author: jiu
@contact: 643562684@qq.com
@time: 2022/3/14 
"""
import os
import re
import time

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
# from selenium.webdriver import ActionChains, Keys
from selenium.webdriver.support.select import Select
# from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.support import expected_conditions as EC

from Conf.setting import *
from common.log import logger
from common.read_Ini import Read_InI

# from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.support.wait import WebDriverWait


class BasePage:
    """
        公共页面类 封装页面的点击点击,等待,截图登方法,页面存在的方法,send,....   这次用第二种方法封装

    """
    element_data = {}
    locater_data = {}

    # 全局审核材料 容器用于后面对于后台进行对应的审核顺序
    audit_materials = []

    # 其他人断言认真的容器
    other_authentication = {
        "register": [],
        "login": [],
    }
    #  全局init对象
    _project = Read_InI(PROJECT_CONF_SETTING["project"])

    def __init__(self, comm: WebDriver):
        self.driver = comm

    def wait_element_visible(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                             page_action: str = ''):
        """
            元素是否可见
        :param locator:  元素定位参数 元祖类型
        :param timeout:  页面定位超时世间
        :param poll_frequency:  查询元素轮询周期
        :param page_action: 操作动作用例如:   百度首页等待输入框
        :return:
        """
        logger.info(" {} :，等待元素:{} 可见开始。".format(page_action, locator))
        start_time = time.time()
        try:
            WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
                EC.visibility_of_element_located(locator))
        except:
            logger.exception(f"页面元素等待可见失败!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(" {} ，等待元素：{} 可见成功,耗时为{}。".format(page_action, locator, time.time() - start_time))

    def wait_page_contains_element(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                                   page_action: str = ''):
        """
            元素是否存在
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :return:
        """
        logger.info("在 {} ，等待元素：{} 存在开始。".format(page_action, locator))
        start_time = time.time()
        try:
            WebDriverWait(self.driver, timeout=timeout, poll_frequency=poll_frequency).until(
                EC.presence_of_element_located(locator))
        except:
            logger.exception(f"页面元素等待存在失败!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info("在 {} ，等待元素：{} 可见成功,耗时为{}。".format(page_action, locator, time.time() - start_time))

    def get_element(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                    page_action: str = '', wait=None):
        """
            获取元素
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :param wait: 元素课件和元素存在的标识
        :return:
        """
        if wait:
            self.wait_page_contains_element(locator, timeout, poll_frequency, page_action)
        else:
            self.wait_element_visible(locator, timeout, poll_frequency, page_action)

        logger.info("{} ，查找元素：{}".format(page_action, locator))
        try:
            val = self.driver.find_element(*locator)

        except:
            logger.exception("获取元素是失败!!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"元素获取成功: {page_action}")
            return val

    def get_text(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                 page_action: str = '', wait=True):

        """
             获取元素的 text值  这个里获取元素的 txt 默认的是元素存在就好
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :return:
        """
        el = self.get_element(locator, timeout, poll_frequency, page_action, wait)
        logger.info(" {} ，获取元素：{} 文本信息".format(page_action, locator))
        try:
            text = el.text
        except:
            logger.exception("获取元素文本信息失败!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"获取的文本信息为:{text}")
            return text

    def element_input(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                      page_action: str = '', value: str = ''):
        """
            文本框输入
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :return:
        """
        el = self.get_element(locator, timeout, poll_frequency, page_action)
        logger.info("{} ，定位元素：{} 输入文本信息".format(page_action, locator))
        try:
            el.clear()
            el.send_keys(value)
        except:
            logger.exception("文本信息输入失败!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"输入的文本信息为: {value}")

    def send_enter(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                   page_action: str = '', value: str = ''):
        """
                  文本框输入 加上敲回车的动作
              :param locator:
              :param timeout:
              :param poll_frequency:
              :param page_action:
              :return:
              """
        el = self.get_element(locator, timeout, poll_frequency, page_action)
        logger.info("{} ，定位元素：{} 输入文本信息".format(page_action, locator))
        try:
            el.clear()
            el.send_keys(value)
            logger.info("输入回车按键")
            el.send_keys(Keys.ENTER)
        except:
            logger.exception("文本信息输入失败!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"输入的文本信息为: {value}")

    def get_el_attribute(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                         page_action: str = '', attr: str = ''):
        """
            获取元素属性
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :param attr:  想要获取的元素属性
        :return:
        """
        el = self.get_element(locator, timeout, poll_frequency, page_action)
        logger.info("在 {} ，定位元素：{} 获取元素属性信息".format(page_action, locator))
        try:
            res = el.get_attribute(attr)
        except:
            logger.exception("元素属性获取失败!!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"属性的值为:{res}")
            return res

    def el_click(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                 page_action: str = ''):
        """
            元素点击
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :return:
        """

        el = self.get_element(locator, timeout, poll_frequency, page_action)
        logger.info(" {} ，定位元素：{} 进行点击".format(page_action, locator))
        try:
            el.click()
        except:
            logger.exception("元素点击失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"{page_action} :点击成功")

    @property
    def ths_window(self):
        """当前窗体对象"""
        logger.info("获取当前窗体对象")
        try:
            hand = self.driver.current_window_handle
        except:
            logger.exception("当前窗体获取失败")
            raise
        else:
            logger.info(f"当前窗体为: {hand}")
            return hand

    @property
    def all_windows(self):
        """所有窗体对象"""
        logger.info("获取所有窗体对象")
        try:
            all_hand = self.driver.window_handles
        except:
            logger.exception("所有长提获取失败")
            raise
        else:
            logger.info(f"所有窗体获取成功: {list(all_hand)}")

    def switch_window_index(self, window_index: int, page_action: str = ''):
        """
            再知道窗体下标点的情况下切换窗体
            切换到 登入窗体  , 窗体下表为 index
        :param window:
        :return:
        """
        logger.info(f"{page_action} 窗体,窗体的下表为: {window_index}")
        try:
            self.driver.switch_to.window(self.all_windows)
        except:
            logger.exception(f"窗体切换失败: 当前的窗体为: {self.driver.title}  !!")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f'窗户切换成功当前窗体的标题为: {self.driver.title}')

    def switch_by_title(self, title_name: str = '', page_action: str = ''):
        """
            根据标题切换窗体
        :param title_name:
        :param page_action:
        :return:
        """
        logger.info(f"切换窗体到: {title_name}")
        try:
            for win in self.all_windows:
                if EC.title_contains(win)(self.driver):
                    break
                self.driver.switch_to.window(win)
        except:
            logger.exception(f"{title_name}: 窗体切换失败, 当前的窗体是: {self.driver.title}")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"窗体切换成,当前窗体为: {self.driver.title}")

    def select_el(self, locator: tuple = (), get_type: str = '', el_value: str = '', timeout: int = 10,
                  poll_frequency: float = 0.5,
                  page_action: str = ''):
        """
           select 选择元素
        :param locator:
        :param timeout:
        :param poll_frequency:
        :param page_action:
        :param get_type:  获取下拉列表的方式
        :param el_value: 获取元素的值
        :return:
        """
        el = self.get_element(locator, timeout, poll_frequency, page_action)
        logger.info(f"{page_action} 的,元素属性为: {locator}")
        try:
            if get_type == 'index':
                logger.info(f"选择的方式为 index 获取")
                Select(el).select_by_value(str(el_value))
            elif get_type in ["visible_text", 'visible']:
                logger.info(f"选择的方式为 {get_type} 获取")
                Select(el).select_by_visible_text(el_value)
            elif get_type == "option":
                logger.info(f"选择的方式为 option 获取")
                Select(el).select_by_value(el_value)
            else:
                raise TypeError
        except:
            logger.info(f"{page_action} 的下拉列表属性获取失败,定位为: {locator}, 获取值得类型为: {get_type},值为: {el_value}")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"{page_action} 的下拉列表的属性,获取成功")

    def switch_frame(self, locator: tuple = (), timeout: int = 10, poll_frequency: float = 0.5,
                     page_action: str = '', ):
        """frame 元素切换"""
        el = self.get_element(locator, timeout, poll_frequency, page_action)
        logger.info(f"信息: {page_action}, 定位属性为: {locator}")
        try:
            self.driver.switch_to.frame(el)
        except:
            logger.exception(f"切换窗体失败:定位元素值为: {locator}")
            self.get_page_img(page_action)
            raise
        else:
            logger.info("frame窗体切换成功")

    def exit_frame_window(self, page_action: str = ''):
        """
            退出 frame 的窗体
        :param page_action:
        :return:
        """
        logger.info(page_action)
        try:
            self.driver.switch_to.default_content()
        except:
            logger.exception("frame 窗体退出失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info("frame 窗体退出成功")

    def popup_alert(self):
        """ 切换alert 弹窗"""
        logger.info("切换到 alert 弹窗")
        try:
            aler = self.driver.switch_to.alert
        except:
            logger.exception("alert 弹窗切换失败!!")
            raise
        else:
            logger.info("alert弹窗切换成功!")
            return aler

    def get_alert_text(self, page_action: str = ''):
        """获取alert的 文本信息"""
        logger.info(f"{page_action},alert 的文本信息")
        try:
            text = self.popup_alert()
        except:
            logger.exception("alert 弹窗文本获取失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"alert 的文本信息获取成功为: {text}")
            return text

    def alert_dismiss(self, page_action: str = ''):
        """alert 弹窗点击取消"""
        logger.info(f"{page_action} alert 点击取消弹窗")
        try:
            self.popup_alert().dismiss()
        except:
            logger.exception(f"取消弹窗点击失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"{page_action} 操作成功")

    def alert_accept(self, page_action: str = ''):
        """alert 弹窗点确定"""
        logger.info(f"{page_action} 操作")
        try:
            self.popup_alert().accept()
        except:
            logger.exception(f"确定弹窗点击失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"{page_action} 弹窗点击成功")

    def get_page_img(self, page_action: str = ''):
        # 图片存储的格式为: {XX页面_XX操作}_截图时间.png
        cur_time = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime())
        file_path = os.path.join(SAVE_SCREENSHOT_PATH, "{}_{}.png".format(page_action, cur_time))
        self.driver.save_screenshot(file_path)
        logger.info("截图保存在：{}".format(file_path))

    def execute_js(self, js: str = '', *args):
        """执行js的代码"""
        logger.info(f"js:执行,js_code: {js},args: {args}")
        try:
            self.driver.execute_script(js, args)
        except:
            logger.exception(f"js代码执行失败: {js}")
            # self.get_page_img(page_action)
            raise
        else:
            # logger.info(f"js执行成功 :{page_action}")
            logger.info(f"js 代码：{js},执行成功")

    def browser_back(self, page_action: str = ''):
        """浏览器后退"""
        logger.info(f"{page_action}, [:浏览器后退操作]")
        try:
            self.driver.back()
        except:
            logger.exception("浏览后退失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info("浏览器后退成功")

    def browser_close(self, page_action: str = ''):
        """浏览器close  页面有弹窗的时候close 会报错"""
        logger.info(f"{page_action}, [:浏览close操作]")
        try:
            self.driver.close()
        except:
            logger.exception(f"浏览器页面close 失败 : {page_action}")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"浏览器标签页关闭成功: {page_action}")

    def browser_quit(self, page_action: str = ''):
        """结束浏览器进程"""
        logger.info(f"浏览器进程结束quit: {page_action}")
        try:
            self.driver.quit()
        except:
            logger.exception("浏览器进程结束失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info("浏览器进程结束成功")

    def browser_exit(self, page_action: str = ''):
        """
            浏览器退出
        :param page_action:
        :return:
        """
        logger.info("浏览器进程结束: [close,quit]")

        self.browser_close(page_action)
        self.browser_quit(page_action)

        logger.info(f"浏览器对象关闭成功[close,quit]")

    def open_url(self, url: str = '', page_action: str = ''):
        """打开url"""
        logger.info(f"{page_action}: [打开url :{url}]")
        try:
            self.driver.get(url)
        except:
            logger.exception(f"url 打开失败: {url}")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"url: {url} 打开成功")

    @property
    def get_page_html(self):
        logger.info("获取网页的源代码")
        try:
            html = self.driver.page_source
        except:
            logger.exception("网页源代码获取失败")
            # self.get_page_img(page_action)
            raise
        else:
            logger.info(f"网页代码获取成获取的是: {self.driver.title} 的html代码")
            return html

    def action_change(self, page_action: str = ''):
        """鼠标初始化"""
        logger.info(f"{page_action} : [鼠标操作初始化]")
        try:
            ac = ActionChains(self.driver)
        except:
            logger.info(f"{page_action} : [鼠标事件初始化失败]")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"鼠标元素初始化成功")
            return ac

    def move_to_element(self, locator: tuple = (), page_action: str = ''):
        """鼠标移动"""
        ac = self.action_change(page_action)
        el = self.get_element(locator=locator, page_action=page_action)
        logger.info(f"{page_action}: [鼠标移动]")
        try:
            ac.move_to_element(el).perform()
        except:
            logger.exception(f"{page_action} 操作失败,元素定位为: {locator}")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"元素移动成功: {page_action}")

    def el_whether_display(self, locator: tuple = (), page_action: str = ''):
        """元素是否显示 ,返回的是 true/false"""
        logger.info(f"{page_action} ,定位元素表达式为: {locator}")
        try:
            status = self.get_element(locator=locator, page_action=page_action).is_displayed()
        except:
            logger.exception(f"{page_action} , 是否存在执行失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"{page_action} :操作成功的:元素课件结果为: {status}")
            return status

    def browser_flash(self, page_action: str = ''):
        """页面刷新"""
        logger.info(page_action)
        try:
            self.driver.refresh()
        except:
            logger.exception(f"{page_action} 失败")
            self.get_page_img(page_action)
            raise
        else:
            logger.info(f"{page_action} 成功")
            return self

    def re_get_text(self, patter: str = '', to_str=None, page_action: str = ''):
        """正则表达式获取页面的值"""
        logger.info(f"{page_action}")
        try:
            if not to_str:
                _text = re.findall(patter, self.get_page_html)
            else:
                _text = re.findall(patter, to_str)
        except:
            logger.exception("正则表达式获取元素失败")
            raise
        else:
            logger.info(f"{page_action} 成功,值为: {_text}")
            return _text

    @property
    def get_window_size(self):
        """获取窗体大小"""
        logger.info("获取窗体大小")
        try:
            size = self.driver.get_window_size()
        except:
            logger.exception("窗体大小获取失败")
            raise
        else:
            logger.info(f"窗体大小获取成功, 宽为: {size['width']}, 长为: {size['height']}")
            return {"width": size['width'], "height": size['height']}

    def set_window_size(self, width=None, height=None, windowHandle='current', pack_action=None):
        """设置浏览器大小"""
        logger.info(f"{pack_action}, width: {width}, height:{height}")
        try:
            self.driver.set_window_size(width=width, height=height, windowHandle=windowHandle)
        except:
            logger.exception("窗体大小设置失败!!")
            raise
        else:
            logger.info(f"窗体大小设置成功现在的大小为, width: {width}, height: {height}")
            return self
